#pragma once
#include <vector>
#include <fstream>
#include <atomic>
#include <iostream>
#include <sstream>
#include <memory>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <string>
#include <boost/algorithm/string.hpp>
#include <unistd.h>
#include "log.hpp"


using namespace ns_log;
namespace ns_util
{

    class TimeUtil
    {
    public:
        /*
            @brief 获取时间戳
            */
        static std::string getTimeStamp()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);

            return std::to_string(_time.tv_sec);
        }
        /*
            @brief 获得毫秒级的时间戳
        */
        static std::string getTimeMS()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            return std::to_string(_time.tv_sec * 1000 + _time.tv_usec / 1000);
        }
    };
    const std::string tempPath = "./temp/";
    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &fileName, const std::string &suffix)
        {
            return tempPath + fileName + suffix;
        }
        /*
            @brief 构建文件 +后缀名的完整文件路径
        */
        static std::string Src(const std::string &fileName)
        {
            return AddSuffix(fileName, ".cpp");
        }

        /*
            @brief 构建可执行程序的完整路径 + 后缀
        */
        static std::string Exe(const std::string &fileName)
        {
            return AddSuffix(fileName, ".exe");
        }

        static std::string CompilerError(const std::string &fileName)
        {
            return AddSuffix(fileName, ".compiler_error");
        }

        // *************** 运行时需要的临时文件 *******************
        static std::string Stdin(const std::string &fileName)
        {
            return AddSuffix(fileName, ".stdin");
        }
        static std::string Stdout(const std::string &fileName)
        {
            return AddSuffix(fileName, ".stdout");
        }
        /*
 @brief 构建该执行程序的标准错误完整路径 + 后缀

*/
        static std::string Stderr(const std::string &fileName)
        {
            return AddSuffix(fileName, ".stderr");
        }
    };

    class FileUtil
    {
    public:
        static bool isFileExists(const std::string &pathName)
        {
            struct stat st;
            return stat(pathName.c_str(), &st) == 0;
        }

        static std::string uniqFileName()
        {
            // * 1. 获得毫秒级的时间戳, 来保证唯一性
            auto ms = TimeUtil::getTimeMS();
            // * 2. 保证原子性
            static std::atomic_uint id(0);
            id++;

            auto uniq_id = std::to_string(id);
            return ms + "_" + uniq_id;
        }
        static bool writeFile(const std::string &target, const std::string &content)
        {
            std::ofstream out(target);
            if (!out.is_open())
            {
                LOG(ERROR) << "writefile 文件打开错误" << std::endl;
                return false;
            }
            out.write(content.c_str(), content.size());
            out.close();
            return true;
        }

        static bool readFile(const std::string &target /*还可能需要其他的参数*/, std::string *content, bool keep = false)
        {
            content->clear();
            std::ifstream in(target);
            // LOG(DEBUG) << target << std::endl;
            if (!in.is_open())
            {
                LOG(ERROR) << "readfile 文件打开错误" << std::endl;
                return false;
            }
            std::string line;
            // std::getline 不保存分隔符, 有些时候需要保留分隔符
            while (std::getline(in, line))
            {
                (*content) += line;
                (*content) += (keep ? "\n" : "");
            }
            in.close();
            return true;
        }

        static void removeTempFile(const std::string &fileName)
        {
            // *清理文件的个数是不确定的，但是有哪些我们是知道的
            std::vector<std::string> tempPath{
                PathUtil::Exe(fileName),
                PathUtil::CompilerError(fileName),
                PathUtil::Src(fileName),
                PathUtil::Stderr(fileName),
                PathUtil::Stdin(fileName),
                PathUtil::Stdout(fileName)
            };

            for (auto& tpath : tempPath)
            {
                if (FileUtil::isFileExists(tpath))
                {
                    unlink(tpath.c_str());
                }
            }
        }
    };

    class StringUtil{
        public:
        /*
            @param str 输入型。待切分的目标
            @param target 存放切分好后的数据的容器(std::vector<std::string>*)
            @param sep 切分标志 默认是空格
        */
        static void splitString(const std::string& str, 
            std::vector<std::string>* target, 
            std::string sep = " ")
        {
            boost::split(*target, str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }
    };

}